home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus Special 26 / AMIGAplus Sonderheft 26 (2000)(Falke)(DE)(Track 1 of 2)[!].iso / PublicDomain / Anwendungen / BareED / source / AsyncStartup.c next >
C/C++ Source or Header  |  1999-11-21  |  20KB  |  708 lines

  1. /*
  2.     Startup-code for BareED
  3.     Written 10 & 11/99 by Jörg van de Loo, Hövel 15, 47559 Kranenburg, FRG.
  4.  
  5.     This  startup-code  is  freeware  and  it's especially written in mind the
  6.     MaxonC++ compiler V4 (useful for C and ANSI-C modes only).
  7.  
  8.     CLI parser 'borrowed' from AZTEC-C package (modified).
  9.  
  10.     This  startup  codes  sets  up  argc, argv with the commandline parameters
  11.     given   through  the  CLI  and  with  all  selected  files  given  through
  12.     Workbench,  e.g. double click on project icon or shift select. Additional,
  13.     it ensures the present of a 68020 processor and Kickstart 2.0 (beta).
  14.  
  15.     No  stdin,  stdout, stderr terminals will be set up since they are useless
  16.     for BareED.
  17.  
  18.     SysBase  and  ExecBase  are  only  present  within this startup-code; this
  19.     ensures  that the additional code of BareED doesn't refer to the variables
  20.     set  up  by  the  startup-code.  This  is due to the fact that my compiler
  21.     would  otherwise  address  them  as 32 bit addresses, that will cause each
  22.     time  a  reloc32  hunk  entry.  What  I  do  is  to refer to _DOS_Base and
  23.     _Exec_Base  once,  to set up DOSBase and SysBase in the additional code of
  24.     BareED,  so  that  my compiler will them address from now on within BareED
  25.     indirect to the processor register a4.
  26.  
  27.     When  you  compile  this  startup-code  ensure  that  no  68020  or higher
  28.     instructions  are  used  before the processor check is executed, otherwise
  29.     on a plain 68000 processor this startup-code will fail with a GURU.
  30.  
  31.     This  startup-code  checks  for  the amount of free stack, too. Since this
  32.     startup-code  uses  very  less stack (56 bytes when running and only up to
  33.     328  bytes  while  setting up variables) it should be enought when using a
  34.     stack  size  of only 4096 bytes for the loadfile of BareED, even under 3rd
  35.     party  graphic  emulation  systems  -  which  in fact do require much more
  36.     stack  than the native Amiga OS 3 graphic system (up to 3Kb when BareED is
  37.     running).
  38.  
  39.     One  goal  of  this  startup-code is, that it gains at lot of stack (up to
  40.     1.1  Kb)  compared  to  the original startup-code that comes along with my
  41.     compiler.
  42.     Currently  it needs a given stack size of 4052 bytes when started off a CLI
  43.     surround and 4046 bytes when started off the Workbench.
  44.  
  45.     11/99  -  modified  this  startup-code  to run-back when started off a CLI
  46.     window  or  called  with  RunCommand()  or  within  a  batch  script of an
  47.     application.
  48.  
  49.     If  you  are able to adapt this startup-code to your compiler please do me
  50.     a  favour and return the adapted startup-code for free to me, in this case
  51.     e-mail Marc Berson at:
  52.         BersonM@aol.com
  53.     and state clearly that the message is for me and concerned BareED.
  54.  
  55.     NOTE: startup.c/BareED.c  can  be only compiled under GNU-C in large mode!
  56.           This is due to a bug in GNU-C; spilled registers.
  57.           I  used  the  GNU-Compiler  that  can  be  found on Geek Gadgets II.
  58.           Thanks to Mr. Fish for this compilation.
  59. */
  60.  
  61.  
  62. #include <exec/execbase.h>
  63. #include <exec/libraries.h>
  64. #include <exec/memory.h>
  65.  
  66. #include <dos/dosextens.h>
  67. #include <dos/dostags.h>
  68.  
  69. #include <utility/tagitem.h>
  70.  
  71. #include <clib/exec_protos.h>
  72. #include <clib/dos_protos.h>
  73.  
  74. #ifdef __GNUC__
  75. #include <pragmas/exec_pragmas.h>
  76. #include <pragmas/dos_pragmas.h>
  77. #else
  78. #include <pragma/exec_lib.h>
  79. #include <pragma/dos_lib.h>
  80. #endif
  81.  
  82. #include <dos/dosextens.h>
  83.  
  84. #include <workbench/startup.h>
  85.  
  86. struct ExecBase   *_Exec_Base;
  87. struct DosLibrary *_DOS_Base;
  88. struct Message      *WBenchMsg;
  89.  
  90. #ifdef __MAXON__
  91.   #ifndef __cplusplus
  92.     static struct ExecBase     *SysBase;    // Allow only to appear within startup.c
  93.     static struct DosLibrary *DOSBase;    // Allow only to appear within startup.c
  94.   #else
  95.     extern struct ExecBase     *SysBase;
  96.     extern struct DosLibrary *DOSBase;
  97.   #endif
  98. #endif
  99.  
  100. #ifndef __MAXON__
  101.     extern struct ExecBase     *SysBase;
  102.     extern struct DOSLibrary *DOSBase;
  103. #endif
  104.  
  105.  
  106. static BPTR  _prg_dir;                // Remembered start dir
  107. static unsigned int    _argc,  _arg_len;
  108. static unsigned char **_argv, *_arg_lin;
  109.  
  110. #ifdef __MAXON__
  111.     extern "C" void GetBaseReg( void);
  112.     #define geta4() GetBaseReg()
  113. #else
  114.     extern geta4();
  115. #endif
  116.  
  117. struct LaunchStuff
  118. {
  119.     int        nextHunk;
  120.     int        hunkSize;
  121.     char    name[128];
  122.     int        stack;
  123.     int        pri;
  124.     int        dummy;        // To make this table divisible by 8
  125. };
  126.  
  127. struct LaunchStuff *LS = 0;
  128. struct Process *MasterTask;
  129.  
  130. unsigned char DOSName[]                = "dos.library";
  131. static unsigned char Console[]        = "CON:0/0/320/80/ERROR REPORT/AUTO/CLOSE/WAIT";
  132. static unsigned char NotEnoughtMem[]= "ERROR: Not enought memory!\n";
  133. static unsigned char NotEnoughtStack[]= "ERROR: Stack < 4096 bytes!\n";
  134. static unsigned char WrongCPU[]        = "ERROR: CPU < 68020!\n";
  135. static unsigned char WrongLIB[]        = "ERROR: Library versions < 36!\n";
  136. static unsigned char WrongSYS[]        = "ERROR: System version < 36!\n";
  137. static unsigned char WrongError[]    = "ERROR: Non describt fault!\n";    // ????
  138.  
  139.  
  140. void _main_jmp( unsigned long parlen, unsigned char *parameter);
  141. int main( unsigned long argc, unsigned char **argv);
  142.  
  143.  
  144. // ################################################################
  145.  
  146. #ifdef __GNUC__
  147. void INIT_0_run_me_at_first_place( unsigned long parlen __asm("d0"), unsigned char *parameter __asm("a0") )
  148. #else
  149. void INIT_0_run_me_at_first_place( register __d0 unsigned long parlen, register __a0 unsigned char *parameter)
  150. #endif
  151. {
  152.     #ifndef __GNUC__    // Since GNU-C does not allow to compile BareED as base relative code
  153.     geta4();
  154.     #endif
  155.  
  156.     _Exec_Base = SysBase = *((struct ExecBase **) 4);    // From memory location 4 to exec library
  157.     if (_Exec_Base -> LibNode . lib_Version <= 32)        // Kickstart lower than 33 (OS1.2) = die
  158.         return;                                            // -> perhaps with a GURU (when started from WB)
  159.  
  160.      _main_jmp( parlen, parameter);    // We never return! We jump to _main_jmp because if
  161.                                     // we would do here the following stuff, d0 and a0
  162.                                     // would be ever pre-reserved, which blows up the
  163.                                     // objectfile un-necessary
  164. }
  165.  
  166. // ################################################################
  167.  
  168. /* Following code is to avoid reloc32 entries - since they would otherwise
  169.    (when linked with the objectfiles) called via "jsr" and not via "bsr" */
  170.    
  171. static unsigned int strlenNR( register const unsigned char *str)
  172. {
  173.     register unsigned int i = 0;
  174.  
  175.     while (*str++)
  176.         i++;
  177.     return i;
  178. }
  179.  
  180. static void strncpyNR( register unsigned char *d, register const unsigned char *s, register unsigned int i)
  181. {
  182.     while (i)
  183.     {
  184.         *d++ = *s++;
  185.         i--;
  186.     }
  187.     *d = 0;
  188. }
  189.  
  190. static void strcpyNR( register unsigned char *d, register const unsigned char *s)
  191. {
  192.     while (*s)
  193.         *d++ = *s++;
  194.     *d = 0;
  195. }
  196.  
  197. /* static void strcatNR( register unsigned char *d, register const unsigned char *s)
  198. {
  199.     while (*d)
  200.         *d++;
  201.     
  202.     while( *s)
  203.         *d++ = *s++;
  204.     *d = 0;
  205. } */
  206.  
  207. static void strncatNR( register unsigned char *d, register const unsigned char *s, register unsigned int i)
  208. {
  209.     while (*d)
  210.         *d++;
  211.     
  212.     while( i)
  213.     {
  214.         *d++ = *s++;
  215.         i--;
  216.     }
  217.     *d = 0;
  218. }
  219.  
  220. // ################################################################
  221.  
  222. /* Function required by GNU-C linker, not necessary anymore - since
  223.    all work already done by this startup-code! */
  224.  
  225. #ifdef __GNUC__
  226. void __main( int argc, char **argv)
  227. {
  228.  return;
  229. }
  230. #endif
  231.  
  232. // ################################################################
  233.  
  234. /* Taken without permission from the AZTEC-package, which in fact
  235.    can be found in books and magazins, too */
  236.  
  237. static void _cli_parse(struct Process *pp, unsigned long alen, register unsigned char *aptr)
  238. {
  239.     register unsigned char *cp;
  240.     register struct CommandLineInterface *cli;
  241.     register unsigned char c;
  242.  
  243.     cli = (struct CommandLineInterface *) ( (unsigned long) pp->pr_CLI << 2);
  244.     cp = (unsigned char *) ( (unsigned long) cli->cli_CommandName << 2);
  245.  
  246.     _arg_len = (unsigned char) cp[0] + alen + 2;
  247.  
  248.     if ( (_arg_lin = (unsigned char *) AllocMem( ((_arg_len + 7) & -8), (0x10000) ) ) == 0)
  249.         return;
  250.  
  251.     c = cp[0];
  252.     strncpyNR( _arg_lin, cp + 1, c);
  253.     _arg_lin[c] = ' ';
  254.     _arg_lin[c + 1] = 0;
  255.     strncatNR( _arg_lin, aptr, alen);
  256.     _arg_lin[c] = 0;
  257.  
  258.     for (_argc = 1, aptr = cp = _arg_lin + c + 1; ; _argc++)
  259.     {
  260.         while ( (c = *cp) == ' ' || c == '\t' || c == '\f' || c == '\r' || c == '\n')
  261.             cp++;
  262.         if (*cp < ' ')
  263.             break;
  264.         if (*cp == '"')
  265.         {
  266.             cp++;
  267.             while ( (c = *cp++) )
  268.             {
  269.                 *aptr++ = c;
  270.                 if (c == '"')
  271.                 {
  272.                     if (*cp == '"')
  273.                     {
  274.                         cp++;
  275.                     }
  276.                     else
  277.                     {
  278.                         aptr[-1] = 0;
  279.                         break;
  280.                     }
  281.                 }
  282.             }
  283.         }
  284.         else
  285.         {
  286.             while ( (c = *cp++) && c != ' ' && c != '\t' && c != '\f' && c != '\r' && c != '\n')
  287.                 *aptr++ = c;
  288.             *aptr++ = 0;
  289.         }
  290.         if (c == 0)
  291.             --cp;
  292.     }
  293.  
  294.     *aptr = 0;
  295.     if ( (_argv = (unsigned char **) AllocMem( (((_argc + 1) * 4 + 7) & -8 ), (0x10000) ) ) == 0 )
  296.     {
  297.         _argc = 0;
  298.         return;
  299.     }
  300.  
  301.     for (c=0, cp=_arg_lin; c < _argc; c++)
  302.     {
  303.         _argv[c] = cp;
  304.         cp += strlenNR( cp) + 1;
  305.     }
  306.  
  307.     _argv[c] = 0;
  308. }
  309.  
  310. // ################################################################
  311.  
  312. /* Allows several Workbench passed in arguments for BareED */
  313.  
  314. static void _wb_parse( struct WBStartup *msg)
  315. {
  316.     int numargs, len, i;
  317.     char str[256], *curr;    // Normally I'm against arrays on stack, but since we're
  318.                             // at front of a loadfile it doesn't matter (because there
  319.                             // is enough free stack available) and we can here avoid
  320.                             // memory fragmentation through AllocMem()
  321.  
  322.     numargs = msg -> sm_NumArgs; 
  323.     _arg_len = (numargs + 2) * 4;    // Number of arguments into amount bytes (plus 2 longwords)
  324.  
  325.  
  326.     /* Get length in bytes of all arguments including zero bytes and drawer terminators */
  327.     i = 0;
  328.     while (i < numargs)
  329.     {
  330.         if (msg -> sm_ArgList[i] . wa_Lock)
  331.             NameFromLock( msg -> sm_ArgList[i] . wa_Lock, &str[0], 255);
  332.         _arg_len += strlenNR( &str[0]);
  333.         _arg_len += 2;    // For zero byte and perhaps for drawer terminator "/" !
  334.         _arg_len += strlenNR( msg -> sm_ArgList[i] . wa_Name);
  335.         i++;
  336.     }
  337.  
  338.     /* Allocate needed space for strings */
  339.     _arg_lin = (unsigned char *) AllocMem( ((_arg_len + 7) & -8), (0x10000) );
  340.     if ( !_arg_lin)
  341.         return;
  342.  
  343.     _argc = numargs;
  344.     _argv = (unsigned char **) _arg_lin;
  345.     curr = _arg_lin + ((numargs + 2) * 4);
  346.  
  347.     /* Create and copy drawer and filenames into allocated memory, behind the argument pointers! */
  348.     i = 0;
  349.     while (i < numargs)
  350.     {
  351.         _argv[i] = curr;
  352.         if (msg -> sm_ArgList[i] . wa_Lock)
  353.         {
  354.             NameFromLock( msg -> sm_ArgList[i] . wa_Lock, &str[0], 255);
  355.             strcpyNR( curr, &str[0]);
  356.             len = strlenNR( curr);
  357.  
  358.             if ( curr[ len - 1] != ':')
  359.             {
  360.                 curr[len] = '/';
  361.                 len ++;
  362.             }
  363.         }
  364.         else
  365.         {
  366.             len = 0;
  367.         }
  368.  
  369.         strcpyNR( curr + len, msg -> sm_ArgList[i] . wa_Name);
  370.         len = strlenNR( curr);
  371.  
  372.         curr += len + 1;    // Behind zero byte
  373.         i++;                // Next arg
  374.     }
  375.  
  376.     _prg_dir = CurrentDir( msg -> sm_ArgList[0] . wa_Lock);        // Set up "progdir:"
  377. }
  378.  
  379.  
  380. // ################################################################
  381.  
  382. /* Print error code down to a console window, if there isn't one yet,
  383.    open one and give the message. */
  384.  
  385. static void GiveFault( int error)
  386. {
  387.     BPTR     newStdOut;
  388.     unsigned char *errorTxt;
  389.  
  390.  
  391.     if (_DOS_Base)        // DOSBase set up?
  392.     {
  393.         errorTxt = 0;
  394.  
  395.         if (_Exec_Base -> LibNode . lib_Version <= 35)    // OS 2.0
  396.             Console[27] = 0;    // No, OS 1.x, so remove AUTO/CLOSE/WAIT from console description
  397.  
  398.         if (WBenchMsg)            // If WB-start, open console window
  399.         {
  400.             newStdOut = Open( Console, MODE_OLDFILE);
  401.         }
  402.         else
  403.         {
  404.             newStdOut = Output();
  405.         }
  406.  
  407.         if (newStdOut)
  408.         {
  409.             if (error == 236)
  410.                 errorTxt = WrongSYS;
  411.             if (error == 105)
  412.                 errorTxt = WrongCPU;
  413.             if (error == 122)
  414.                 errorTxt = WrongLIB;
  415.             if (error == 217)
  416.                 errorTxt = NotEnoughtStack;
  417.             if (error == 103)
  418.                 errorTxt = NotEnoughtMem;
  419.             if (errorTxt == 0)
  420.                 errorTxt = WrongError;    // ????
  421.  
  422.             Write( newStdOut, errorTxt, strlenNR( errorTxt) );
  423.  
  424.             if (WBenchMsg && _Exec_Base -> LibNode . lib_Version <= 35)    // If WB-start and OS 1.x
  425.             {
  426.                 Delay( 5*60);        // Wait a while
  427.                 Close( newStdOut);    // Close console
  428.             }
  429.         }
  430.     }
  431. }
  432.  
  433. // ################################################################
  434.  
  435. /* Un-load startup-code and additional program code/data and bss.
  436.    Free also the table we used, but restore the segment of our
  437.    program first!
  438.    This is only called if we are in 'RunBack' mode. */
  439.  
  440. static void LaunchExit( void)
  441. {
  442.     unsigned int *adr;
  443.  
  444.     adr = (unsigned int *) &(INIT_0_run_me_at_first_place);
  445.     adr --;
  446.     *adr = LS -> nextHunk;    // Restore the link to the additional hunks
  447.     adr --;
  448.     *adr = LS -> hunkSize;    // Restore first hunk's size (was set zero)
  449.  
  450.     FreeMem( LS, sizeof( struct LaunchStuff));
  451.  
  452.     Forbid();    // Must be called because we may not removed from memory since additional code must be run first!
  453.     adr += 1;    // Point back to segment entry for DOS
  454.     UnLoadSeg( (BPTR) ((unsigned long) adr/4) );
  455. }
  456.  
  457. // ################################################################
  458.  
  459. /* Code to get program's return address and to call it
  460.    That's the 'additional code that must be run first' */
  461.  
  462. static const unsigned short _finally_code[] =
  463. {
  464.  0x2400,                // move.l    D0,D2                    Save error code
  465.  0x93C9,                // suba.l    A1,A1
  466.  0x2C78,0x0004,            // movea.l    (4).w,A6
  467.  0x4EAE,0xFEDA,            // jsr        _LVOFindTask(A6)        Own Task
  468.  0x2040,                // movea.l    D0,A0
  469.  0x2068,0x00B0,            // movea.l    pr_ReturnAddr(A0),A0    Get system's exit address for us
  470.  0x4FE8,0xFFFC,            // lea        -4(A0),sp                Restore initial stack
  471.  0x2002,                // move.l    D2,D0                    Error code to D0
  472.  0x4E75                    // rts                                Back to system
  473. };
  474.  
  475. // ################################################################
  476.  
  477. /* Since  my compiler doesn't allow to overload a function (stub), I use
  478.    a different name: exitNR ! */
  479.  
  480. void exitNR( int error)
  481. {
  482.     #ifdef __GNUC__
  483.     void (* _finally)( int err __asm("d0") );
  484.     #else
  485.     void (* _finally)( register __d0 int err);
  486.     #endif
  487.  
  488.     geta4();
  489.     (void *) _finally = (void *) _finally_code;
  490.  
  491.     if (error)
  492.         GiveFault( error);
  493.  
  494.     ((struct Process *) _Exec_Base ->ThisTask) -> pr_Result2 = error;
  495.  
  496.     if (WBenchMsg)
  497.     {
  498.         if (_arg_lin)
  499.         {
  500.             FreeMem( _arg_lin, ((_arg_len + 7) & -8) );
  501.             if (_prg_dir)    // If it is zero (SYS:) ignore
  502.                 CurrentDir( _prg_dir);        // Lock of basic directory
  503.         }
  504.         Forbid();
  505.         ReplyMsg( WBenchMsg);
  506.     }
  507.     else
  508.     {
  509.         if (_arg_lin)
  510.         {
  511.             FreeMem(_argv, (((_argc + 1) * 4 + 7) & -8) );
  512.             FreeMem(_arg_lin, ((_arg_len + 7) & -8) );
  513.         }
  514.     }
  515.  
  516.     if (_DOS_Base)
  517.         CloseLibrary( (struct Library *) _DOS_Base);
  518.  
  519.     // Check if our application did a detach from a CLI
  520.     if (LS)
  521.         LaunchExit();
  522.  
  523.     _finally( error);
  524. }
  525.  
  526. // ################################################################
  527.  
  528. /* This function does not return to the caller ! */
  529.  
  530. static void CallMainPRG( void)
  531. {
  532.     exitNR( main( _argc, _argv));
  533. }
  534.  
  535. // ################################################################
  536.  
  537. /* If we are in 'RunBack' mode we call the main() function. The code
  538.    below is executed as first part of the new created process. */
  539.  
  540. static void LaunchMain( void)
  541. {
  542.     geta4();
  543.     Signal( (struct Task *) MasterTask, (0x10000));
  544.     CallMainPRG();
  545. }
  546.  
  547. // ################################################################
  548.  
  549. /* Set up necessary thing to provide an auto-detach (RunBack mode).
  550.    This is a little tricky one which cares about the priority and
  551.    stack size of the original process which are the settings for
  552.    the new created.
  553. */
  554.  
  555. static void LaunchStartup( void)
  556. {
  557.     struct MsgPort *msgp;
  558.     struct Process *proc;
  559.     unsigned int *adr;
  560.     struct TagItem tag[5];
  561.     struct CommandLineInterface *cli;
  562.     unsigned char *cp;
  563.  
  564.  
  565.     MasterTask = ((struct Process *) _Exec_Base -> ThisTask);
  566.     LS = (struct LaunchStuff *) AllocMem( sizeof( struct LaunchStuff), MEMF_CLEAR|MEMF_PUBLIC);
  567.     if (!LS)            // No table?
  568.         CallMainPRG();    // We never return!
  569.  
  570.     cli = (struct CommandLineInterface *) ( (unsigned long) MasterTask->pr_CLI << 2);
  571.     cp = (unsigned char *) ( (unsigned long) cli->cli_CommandName << 2);
  572.  
  573.     // Duplicate name: slave task's name equal to master's one
  574.     strncpyNR( LS->name, cp + 1, cp[0]);
  575.     // Duplicate priority
  576.     LS->pri   = MasterTask -> pr_Task . tc_Node . ln_Pri;
  577.     // Duplicate stack size
  578.     LS->stack = (int) MasterTask->pr_Task.tc_SPUpper - (int) MasterTask->pr_Task.tc_SPLower;
  579.  
  580.     // Settings for task to create
  581.     tag[0].ti_Tag = NP_Entry;
  582.     tag[0].ti_Data = (ULONG) &(LaunchMain);
  583.     tag[1].ti_Tag = NP_Name;
  584.     tag[1].ti_Data = (ULONG) LS->name;
  585.     tag[2].ti_Tag = NP_StackSize;
  586.     tag[2].ti_Data = LS->stack;
  587.     tag[3].ti_Tag = NP_Priority;
  588.     tag[3].ti_Data = LS->pri;
  589.     tag[4].ti_Tag = TAG_DONE;
  590.  
  591. /* An AmigaDOS 'Hunk' looks like this (in memory)
  592.     -4 int  HunkSize
  593.      0 BPTR NextHunk    <- The segment starts here (as BPTR), see LoadSeg(), UnLoadSeg(), etc.
  594.     +4 Code/Data/BSS
  595. */
  596.  
  597.     // Create slave task which becomes master task
  598.     msgp = (struct MsgPort *) CreateNewProc( tag);
  599.     if (!msgp)            // Failed to create task?
  600.     {
  601.         FreeMem( LS, sizeof( struct LaunchStuff));
  602.         LS = 0;
  603.         CallMainPRG();    // We never return!
  604.     }
  605.  
  606.     // From message port of process (task) to process itself (slave)
  607.     proc = (struct Process *) ((ULONG) msgp - sizeof( struct Task));
  608.     Wait( (0x10000));        // Wait for slave task to signal this bit so that we can quit savely
  609.  
  610.     // First instruction of this startup-code is at location:
  611.     adr = (unsigned int *) &(INIT_0_run_me_at_first_place);
  612.  
  613.     // Point to BPTR next hunk (seglist start)
  614.     adr --;
  615.     // Remember the hunk address 
  616.     LS -> nextHunk = *adr;
  617.     // Break the hunk list of this loadfile
  618.     *adr = 0;
  619.  
  620.     // Point to size of 'this' hunk (first hunk of loadfile)
  621.     adr --;
  622.     // Remember hunk size (normally code size, it's the HUNK_CODE)
  623.     LS -> hunkSize = *adr;
  624.     // This hunk size forced to zero 
  625.     *adr = 0;
  626.  
  627.     /* Why I did the things above?
  628.         Remember ever that 2 tasks are running which share the same memory and instructions!
  629.  
  630.          If  we  would  now  quit the first by the system (user) created task, the memory and
  631.         therewith  the  instructions  are gone, too. Thus a crash isn't far. What I do is to
  632.         tell  AmigaDOS that the first created process has got only a single hunk with a size
  633.         of  zero  (ok.,  I know I'm a liar) so that AmigaDOS doesn't frees anything when the
  634.         first   created  task  quits.  The  segment  (hunk-list)  is  restored  by  function
  635.         LaunchExit()  and  the  memory  used by it is removed by a call to AmigaDOS function
  636.         UnLoadSeg().  Since  UnLoadSeg()  instantly  gives  the  memory back to the system I
  637.         forbid  task  switching and therwith memory allocation while the 2nd created task is
  638.         staying  alive.  If it dies, the task switching is enabled automatically through the
  639.         system.
  640.     */
  641. }
  642.  
  643. // ################################################################
  644.  
  645. void _main_jmp( unsigned long parlen, unsigned char *parameter)
  646. {
  647.     int error;
  648.     struct Process *proc;
  649.  
  650.  
  651.     error = 0;
  652.     proc = ((struct Process *) _Exec_Base -> ThisTask);
  653.  
  654.     if (proc -> pr_CLI)
  655.     {
  656.         WBenchMsg = 0;
  657.     }
  658.      else
  659.     {
  660.         WaitPort( &proc -> pr_MsgPort);
  661.          WBenchMsg = GetMsg( &proc -> pr_MsgPort);
  662.     }
  663.  
  664.     if (_Exec_Base -> LibNode . lib_Version <= 35)        // Lower Kickstart 2.0 (beta)?
  665.         error = 236;
  666.  
  667.     _DOS_Base = DOSBase = (struct DosLibrary *) OpenLibrary( DOSName, 33);
  668.     if ( !_DOS_Base || _DOS_Base -> dl_lib . lib_Version <= 35)
  669.         error = 122;
  670.  
  671.     // If we have a soft-kicked 2.0 ROM for 1.x machines we raise at least an Exec error (236)
  672.     if (error)
  673.         exitNR( error);
  674.  
  675.     if ( !(_Exec_Base -> AttnFlags & AFF_68020))        // At least a 68020 processor?
  676.         exitNR( 105);
  677.  
  678.  
  679.     // Do we have at least 4000 bytes of stack available? - NOTE: the variable proc is on
  680.     // the top of the stack so using this address is the current upper bound of the stack!
  681.     if ( (((int) proc->pr_Task.tc_SPUpper - (int) proc->pr_Task.tc_SPLower) - ( (int) proc->pr_Task.tc_SPUpper - (int) &proc) ) < 4000 )
  682.         exitNR( 217);
  683.  
  684.     if (WBenchMsg)
  685.     {
  686.         _wb_parse( (struct WBStartup *) WBenchMsg);
  687.         if ( !_arg_lin)
  688.             exitNR( 103);    // Fail: no mem
  689.     }
  690.     else
  691.     {
  692.         _cli_parse( proc, parlen, parameter);
  693.         if ( !_arg_lin)
  694.             exitNR( 103);
  695.     }
  696.  
  697.     if (WBenchMsg)
  698.     {
  699.         CallMainPRG();
  700.     }
  701.             else
  702.     {
  703.         LaunchStartup();    // Try detach from CLI, if it fails, go on normal
  704.     }
  705. }
  706.  
  707. // ################################################################
  708.